﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Remoting;
using System.Text;

namespace Infinity.Common.Extensions
{
	/// <summary>
	/// Extension class for Object
	/// </summary>
	public static class ObjectExtension
	{
		public static bool In(this object obj, params object[] args)
		{
			Ensure.NotNull("obj", obj);
			return args.Any(x => obj != null && obj.Equals(x));
		}

		public static bool NotIn(this object obj, params object[] args)
		{
			Ensure.NotNull("obj", obj);
			return !In(obj, args);
		}

		public static bool Between<T>(this T obj, T start, T end)
			where T : IComparable<T>
		{
			return start.CompareTo(obj) <= 0 && end.CompareTo(obj) >= 0;
		}

		/// <summary>
		/// It converts 'obj' to System.Object
		/// </summary>
		public static object ToObject<T>(this T obj)
		{
			return obj;
		}

		/// <summary>
		/// It returns true if the object is not null reference
		/// </summary>
		public static bool IsNotNull<T>(this T obj)
			where T : class
		{
			return obj != null;
		}

		/// <summary>
		/// It returns true if the object is null reference
		/// </summary>
		public static bool IsNull<T>(this T obj)
			where T : class
		{
			return !obj.IsNotNull();
		}

		public static bool Is<T>(this object obj)
		{
			return obj is T;
		}

		/// <summary>
		/// If type of obj equals T then action is invoked and function returns true. Otherwise it returns false.
		/// </summary>
		public static bool Is<T>(this object obj, Action<T> action)
		{
			if (obj is T)
			{
				action((T)obj);
				return true;
			}
			return false;
		}

		/// <summary>
		/// A more sophisticated 'as' operator
		/// </summary>
		//public static object As<TNew>(this object obj, Action<TNew> action)
		//{
		//    if (obj is TNew)
		//        action((TNew)obj);
		//    return obj;
		//}
		/// <summary>
		/// More sophisticated 'as' operator
		/// </summary>
		public static T As<T, TNew>(this T obj, Action<TNew> action)
		{
			if (obj is TNew)
				action((TNew)obj.ToObject());
			return obj;
		}

		/// <summary>
		/// It converts 'obj' to an explicit value of type. It helps for encapsulating a conversion from T to TNew
		/// </summary>
		public static TNew To<T, TNew>(this T obj, Func<T, TNew> action)
		{
			return Ensure.NotNull("action", action)(obj);
		}
	}
}